<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>智能思维导图工具</title>

  <!-- 引入 markmap-view 的样式 -->
  <!-- 将0.15.3更新为0.18.0版本 -->
  <link rel="stylesheet" href="https://unpkg.com/markmap-view@0.18.0/dist/style.css" />


  <!-- 引入必要的 JavaScript 库 -->
  <script src="d3@6.js"></script>
  <script src="markmap-lib@0.18"></script>
  <script src="markmap-view@0.18"></script>

  <!-- 引入 Font Awesome 图标库 -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />

  <!-- 引入 PDF 导出库 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>

  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }

    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      background: linear-gradient(135deg, #1e3c72, #2a5298);
      color: #333;
      height: 100vh;
      overflow: hidden;
      touch-action: manipulation;
    }

    .app-container {
      display: flex;
      flex-direction: column;
      height: 100vh;
      width: 100vw;
      padding: 15px;
      max-width: 1600px;
      margin: 0 auto;
    }

    .header {
      padding: 20px;
      text-align: center;
      margin-bottom: 15px;
    }

    .header h1 {
      color: white;
      font-size: 2.5rem;
      font-weight: 700;
      text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    }

    .header p {
      color: #e0e0e0;
      font-size: 1.1rem;
      margin-top: 8px;
    }

    .main-content {
      display: flex;
      flex: 1;
      gap: 20px;
      height: calc(100% - 140px);
    }

    .panel {
      background: rgba(255, 255, 255, 0.92);
      border-radius: 18px;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
      overflow: hidden;
      display: flex;
      flex-direction: column;
      backdrop-filter: blur(10px);
      border: 1px solid rgba(255, 255, 255, 0.18);
    }

    .editor-panel {
      flex: 1.1;
      min-width: 300px;
    }

    .mindmap-panel {
      flex: 2;
    }

    .panel-header {
      padding: 18px 25px;
      background: linear-gradient(90deg, #4a6491, #5c7cb8);
      color: white;
      display: flex;
      justify-content: space-between;
      align-items: center;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);
    }

    .panel-title {
      font-size: 0.9rem;
      font-weight: 400;
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .panel-title i {
      font-size: 0.9rem;
    }

    .toolbar {
      display: flex;
      gap: 15px;
      padding: 10px;
      background: #f8f9fa;
      border-bottom: 1px solid #e0e0e0;
      flex-wrap: wrap;
    }

    .tool-btn {
      background: white;
      border: 1px solid #ddd;
      border-radius: 14px;
      padding: 8px 10px;
      cursor: pointer;
      display: flex;
      align-items: center;
      gap: 10px;
      font-size: 9px;
      color: #444;
      transition: all 0.25s ease;
      min-height: 30px;
      min-width: 30px;
      box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
      font-weight: 500;
    }

    .tool-btn:hover {
      background: #4a6491;
      color: white;
      border-color: #4a6491;
      transform: translateY(-2px);
      box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
    }

    .tool-btn i {
      font-size: 22px;
    }

    #markdown-input {
      flex: 1;
      width: 100%;
      padding: 22px;
      border: none;
      font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
      font-size: 16px;
      line-height: 1.7;
      resize: none;
      background: #fff;
      border-bottom: 1px solid #e0e0e0;
    }

    #markdown-input:focus {
      outline: none;
      background: #fcfdff;
    }

    #markmap-container {
      flex: 1;
      background: #fff;
      position: relative;
      overflow: hidden;
      min-height: 0;
    }

    #markmap-container svg {
      width: 100%;
      height: 100%;
    }

    #markmap-container svg text {
      white-space: pre-wrap !important;
      word-break: break-word !important;
      font-size: 14px !important;
      text-anchor: middle;              /* 居中显示 */
      dominant-baseline: middle;        /* 垂直居中 */
    }
    /* 容器高度优化 */
    #markmap-container {
      min-height: 500px !important;
    }

    .status-bar {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      padding: 8px 10px;
      background: #2ecc71;
      color: white;
      font-size: 9px;
      text-align: center;
      z-index: 1000;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
      transform: translateY(-100%);
      transition: transform 0.3s ease;
      font-weight: 500;
    }

    .status-bar.error {
      background: #e74c3c;
    }

    .status-bar.show {
      transform: translateY(0);
    }

    .zoom-controls {
      position: absolute;
      bottom: 30px;
      right: 30px;
      display: flex;
      flex-direction: column;
      gap: 18px;
      z-index: 100;
    }

    .zoom-btn {
      width: 60px;
      height: 60px;
      border-radius: 50%;
      background: white;
      border: 1px solid #ddd;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
      color: #444;
      transition: all 0.25s ease;
      font-size: 25px;
    }

    .zoom-btn:hover {
      background: #4a6491;
      color: white;
      transform: scale(1.12);
      border-color: #4a6491;
    }

    .checkbox-container {
      display: flex;
      align-items: center;
      gap: 15px;
      background: white;
      padding: 8px 10px;
      border-radius: 14px;
      border: 1px solid #ddd;
      min-height: 30px;
      box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
    }

    .checkbox-container label {
      font-size: 9px;
      font-weight: 500;
      color: #444;
    }

    .export-options {
      display: flex;
      gap: 15px;
      padding: 0 18px 18px;
      background: #f8f9fa;
    }

    .export-btn {
      flex: 1;
      background: #4a6491;
      color: white;
      border: none;
      border-radius: 12px;
      padding: 10px;
      font-size: 10px;
      font-weight: 400;
      cursor: pointer;
      transition: all 0.25s ease;
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
    }

    .export-btn:hover {
      background: #5c7cb8;
      transform: translateY(-2px);
      box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
    }

    .export-btn.md {
      background: #27ae60;
    }

    .export-btn.md:hover {
      background: #2ecc71;
    }


  </style>
</head>
<body>
  <div class="app-container">

    <div class="main-content">
      <!-- Markdown 编辑器面板 -->
      <div class="panel editor-panel">
        <div class="panel-header">
          <div class="panel-title">
            <i class="fas fa-edit"></i>
            <span>Markdown 编辑器</span>
          </div>
        </div>

        <div class="toolbar">
          <button class="tool-btn" id="sample-btn" title="加载示例">
            <i class="fas fa-file-code"></i>
            <span>示例</span>
          </button>
          <button class="tool-btn" id="clear-btn" title="清空">
            <i class="fas fa-trash"></i>
            <span>清空</span>
          </button>
          <button class="tool-btn" id="convert-btn">
            <i class="fas fa-sync-alt"></i>
            <span>转换</span>
          </button>
          <div class="checkbox-container">
            <input type="checkbox" id="auto-convert" checked />
            <label for="auto-convert">自动转换</label>
          </div>
        </div>

        <textarea id="markdown-input" placeholder="在此输入Markdown格式的思维导图..."># 项目计划

## 目标
- 提高生产力
- 改善团队协作
- 提升产品质量

## 任务
1. 研究阶段
    - 市场分析
    - 竞争对手研究
2. 开发
    - 后端API
    - 前端UI
3. 测试
    - 单元测试
    - 集成测试

## 时间线
- Q1: 规划
- Q2: 开发
- Q3: 测试
- Q4: 发布

## 团队
- 产品经理
- 开发人员
    - 前端
    - 后端
- 设计师
- 测试工程师

## 预算
- 资金: $500,000
- 支出: $450,000
- 应急资金: $50,000

## 风险
- 市场变化
- 技术挑战
- 资源限制</textarea>

        <div class="export-options">
          <button class="export-btn md" id="export-md-btn">
            <i class="fas fa-file-export"></i> 导出 Markdown
          </button>
        </div>
      </div>

      <!-- 思维导图展示面板 -->
      <div class="panel mindmap-panel">
        <div class="panel-header">
          <div class="panel-title">
            <i class="fas fa-project-diagram"></i>
            <span>思维导图</span>
          </div>
          <button class="tool-btn" id="save-btn" title="保存">
            <i class="fas fa-save"></i>
            <span>保存</span>
          </button>
        </div>

        <div id="markmap-container"></div>

        <div class="zoom-controls">
          <button class="zoom-btn" id="zoom-in" title="放大">
            <i class="fas fa-plus"></i>
          </button>
          <button class="zoom-btn" id="zoom-out" title="缩小">
            <i class="fas fa-minus"></i>
          </button>
          <button class="zoom-btn" id="zoom-reset" title="重置缩放">
            <i class="fas fa-expand"></i>
          </button>
        </div>

        <div class="export-options">
          <button class="export-btn png" id="export-png-btn">
            <i class="fas fa-file-image"></i> 导出 PNG
          </button>
        </div>
      </div>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function () {
      // 获取页面元素
      const markdownInput = document.getElementById('markdown-input');
      const markmapContainer = document.getElementById('markmap-container');
      const convertBtn = document.getElementById('convert-btn');
      const autoConvertCheckbox = document.getElementById('auto-convert');
      const sampleBtn = document.getElementById('sample-btn');
      const clearBtn = document.getElementById('clear-btn');
      const saveBtn = document.getElementById('save-btn');
      const exportMdBtn = document.getElementById('export-md-btn');
      const exportPngBtn = document.getElementById('export-png-btn'); 
      const zoomIn = document.getElementById('zoom-in');
      const zoomOut = document.getElementById('zoom-out');
      const zoomReset = document.getElementById('zoom-reset');

      // 定时器和markmap实例
      let convertTimeout;
      let markmapInstance = null;
      let svgElement = null;

      // 示例Markdown数据
      const sampleMarkdown = `# 项目计划

## 目标
- 提高生产力
- 改善团队协作
- 提升产品质量

## 任务
1. 研究阶段
    - 市场分析
    - 竞争对手研究
2. 开发
    - 后端API
    - 前端UI
3. 测试
    - 单元测试
    - 集成测试

## 时间线
- Q1: 规划
- Q2: 开发
- Q3: 测试
- Q4: 发布

## 团队
- 产品经理
- 开发人员
    - 前端
    - 后端
- 设计师
- 测试工程师

## 预算
- 资金: $500,000
- 支出: $450,000
- 应急资金: $50,000

## 风险
- 市场变化
- 技术挑战
- 资源限制`;

      // 将Markdown转换为思维导图
      function convertMarkdown() {
        const text = markdownInput.value.trim();
        if (!text) {
          showStatus('编辑器内容为空');
          return;
        }

        try {
          const transformer = new markmap.Transformer();
          const { root } = transformer.transform(text);

          markmapContainer.innerHTML = '';

          svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
          svgElement.id = 'markmap-svg';
          svgElement.style.width = '100%';
          svgElement.style.height = '100%';
          markmapContainer.appendChild(svgElement);

          markmapInstance = markmap.Markmap.create(svgElement, {
            zoom: true,
            pan: true,
            // 新增自动换行配置
            wrap: true,                      // 启用自动换行[2,5](@ref)
            maxWidth: 400,                   // 节点最大宽度(像素)[5](@ref)
            padding: 20,                     
            textColor: "#333",
            fontFamily: "Arial, sans-serif",
            allowForeignObject: true         // 支持复杂文本渲染[8](@ref)
          }, root);

          setupZoomControls();

          showStatus('转换成功');
        } catch (error) {
          console.error('转换错误:', error);
          showStatus(`转换失败: ${error.message}`, true);
        }
      }

      // 设置缩放控制
      function setupZoomControls() {
        if (!markmapInstance || !markmapInstance.zoom) return;

        const zoom = markmapInstance.zoom;

        zoomIn.onclick = () => zoom.scaleBy(1.2);
        zoomOut.onclick = () => zoom.scaleBy(0.8);
        zoomReset.onclick = () => {
          zoom.scaleTo(1);
          zoom.translateTo(0, 0);
        };
      }

      // 显示状态消息
      function showStatus(message, isError = false) {
        const statusBar = document.createElement('div');
        statusBar.className = 'status-bar';
        if (isError) statusBar.classList.add('error');
        statusBar.textContent = message;
        statusBar.classList.add('show');
        document.body.appendChild(statusBar);

        setTimeout(() => {
          statusBar.classList.remove('show');
          setTimeout(() => {
            document.body.removeChild(statusBar);
          }, 300);
        }, 3000);
      }

      // 导出Markdown
      exportMdBtn.addEventListener('click', () => {
        const text = markdownInput.value.trim();
        if (text) {
          const dataStr = 'data:text/markdown;charset=utf-8,' + encodeURIComponent(text);
          const downloadAnchor = document.createElement('a');
          downloadAnchor.setAttribute('href', dataStr);
          downloadAnchor.setAttribute('download', 'mindmap.md');
          document.body.appendChild(downloadAnchor);
          downloadAnchor.click();
          downloadAnchor.remove();
          showStatus('Markdown导出成功');
        } else {
          showStatus('没有可导出的内容', true);
        }
      });

      // 导出PNG
      exportPngBtn.addEventListener('click', function() {
        if (!markmapInstance) {
          showStatus('没有可导出的思维导图', true);
          return;
        }
        showStatus('正在生成PNG图片，请稍候...');
        html2canvas(markmapContainer, {
          scale: 3, // 提高分辨率
          useCORS: true,
          backgroundColor: "#ffffff"
        }).then(canvas => {
          const imgData = canvas.toDataURL('image/png');
          const downloadLink = document.createElement('a');
          downloadLink.href = imgData;
          downloadLink.download = 'mindmap.png';
          document.body.appendChild(downloadLink);
          downloadLink.click();
          document.body.removeChild(downloadLink);
          showStatus('PNG导出成功');
        }).catch(error => {
          console.error('PNG导出错误:', error);
          showStatus('PNG导出失败: ' + error.message, true);
        });
      });



      // 示例按钮
      sampleBtn.addEventListener('click', () => {
        markdownInput.value = sampleMarkdown;
        if (autoConvertCheckbox.checked) {
          convertMarkdown();
        }
      });

      // 清空按钮
      clearBtn.addEventListener('click', () => {
        markdownInput.value = '';
        if (autoConvertCheckbox.checked) {
          convertMarkdown();
        } else {
          markmapContainer.innerHTML = '';
          showStatus('编辑器已清空');
        }
      });

      // 输入事件
      markdownInput.addEventListener('input', () => {
        if (autoConvertCheckbox.checked) {
          clearTimeout(convertTimeout);
          convertTimeout = setTimeout(convertMarkdown, 800);
        }
      });

      // 转换按钮
      convertBtn.addEventListener('click', convertMarkdown);

      // 保存按钮
      saveBtn.addEventListener('click', () => {
        const text = markdownInput.value.trim();
        if (text) {
          localStorage.setItem('md2mind_data', text);
          showStatus('思维导图保存成功');
        } else {
          showStatus('没有可保存的内容', true);
        }
      });

      // 初始化
      const savedData = localStorage.getItem('md2mind_data');
      if (savedData) {
        markdownInput.value = savedData;
        showStatus('已加载保存的数据');
      } else {
        markdownInput.value = sampleMarkdown;
      }

      setTimeout(convertMarkdown, 100);
    });
  </script>
</body>
</html>